package com.xiyuan.smartutils.client.ws.core.impl.rfc6455;

import com.xiyuan.smartutils.client.ws.WebSocketPacket;
import com.xiyuan.smartutils.client.ws.core.WebsocketPacketHeader;

import java.nio.ByteBuffer;

/**
 * @author xiyuan-lgz
 */
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
public class DefaultWebsocketPacket extends WebSocketPacket {
    
    public DefaultWebsocketPacket() {
        super(new byte[0]);
    }
    
    public DefaultWebsocketPacket(String body) {
        super(body);
    }
    
    public DefaultWebsocketPacket(Opcode opcode) {
        super(opcode);
    }
    
    public DefaultWebsocketPacket(byte[] body, Opcode opcode) {
        super(body, opcode);
    }
    
    /**
     * Instantiates a new body frame for opcode.
     *
     * @param body   the custom body.
     * @param header the header.
     */
    public DefaultWebsocketPacket(byte[] body, WebsocketPacketHeader header) {
        super(body, header);
    }
    
    @Override
    public ByteBuffer toByteBuffer() {
        PayloadLengthType lenType = header.getPayloadLengthType();
        long payloadLen = header.getPayloadLength();
        int bodyLength = 0;
        if (body != null) {bodyLength = body.length;}
        
        ByteBuffer buf = ByteBuffer.allocate(2 + header.getPayloadLengthType().offset() + bodyLength + (header.isMask()
                                                                                                        ? 4
                                                                                                        : 0));
        
        // FIN
        buf.put((byte) ((header.isFragmented() ? 0 : 0x80) | header.getOpcode().intValue()));
        
        // payloadLen
        byte maskBit = (byte) (header.isMask() ? 1 << 7 : 0);
        switch (lenType) {
            
            case LEN_SHORT:
                buf.put((byte) (payloadLen | maskBit));
                break;
            case LEN_16:
                buf.put((byte) (lenType.byteValue() | maskBit));
                buf.putShort((short) payloadLen);
                break;
            case LEN_63:
                buf.put((byte) (lenType.byteValue() | maskBit));
                buf.putLong(payloadLen);
                break;
            default:
                break;
        }
        
        if (header.isMask()) {
            // 掩码加密处理
            byte[] mask_key = new byte[4];
            ByteBuffer.wrap(mask_key).putInt(random.nextInt());
            buf.put(mask_key);
            if (body != null) {
                for (int i = 0; i < body.length; i++) {buf.put((byte) (body[i] ^ mask_key[i % 4]));}
            }
        }
        else if (body != null) {
            buf.put(body);
        }
        
        buf.flip();
        return buf;
    }
    
}
